/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 combat_object_model.h

	$Header: /heroes4/combat_object_model.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( COMBAT_OBJECT_MODEL_H_INCLUDED )
#define COMBAT_OBJECT_MODEL_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <cassert>
#include <iosfwd>

#include "image_sequence.h"
#include "map_point.h"
#include "obstacle_type.h"
#include "resource_traits.h"

// --------------------------------------------------------------------------
// t_combat_object_model_base class
// --------------------------------------------------------------------------
class t_combat_object_model_root
{
public:
	// Constructor/Destructor
	t_combat_object_model_root();
	virtual ~t_combat_object_model_root();

	// Static data
	enum { k_max_frames_per_second = 15 };
	enum { k_max_height = 255 };
	enum { k_min_frames_per_second = 1 };
	enum { k_min_height = 0 };

	// Member functions
	bool					blocks_movement() const;
	bool					can_be_destroyed() const;
	bool					can_be_summoned() const;
	static bool				get_combat_has_changed();
	int						get_frames_per_second() const;
	int						get_height() const;
	int						get_ticks_per_frame() const;
	t_obstacle_type			get_type() const;
	bool					hinders_movement() const;
	bool					is_underlay() const;
	bool					obscures_vision() const;
	void					set_blocks_movement( bool arg );
	void					set_can_be_destroyed( bool arg );
	void					set_can_be_summoned( bool arg );
	static void				set_combat_has_changed(bool arg = true);
	void					set_frames_per_second( int new_frames_per_second );
	void					set_height( int new_height );
	void					set_hinders_movement( bool arg );
	void					set_is_underlay( bool new_underlay );
	void					set_obscures_vision( bool arg );
	void					set_type( t_obstacle_type type );
	
protected:
	// Data members
	bool			m_blocks_movement;
	bool			m_can_be_destroyed;
	bool			m_can_be_summoned;	
	static bool		m_combat_has_changed;
	bool			m_hinders_movement;
	int				m_height;
	int				m_frames_per_second;
	bool			m_obscures_vision;
	int				m_ticks_per_frame;
	t_obstacle_type m_type;
	bool			m_underlay;
	
};

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline t_combat_object_model_root::t_combat_object_model_root()
	:   m_height( k_min_height ),
		m_frames_per_second( 10 ),
		m_ticks_per_frame( 100 ),
		m_underlay( false )
{
	m_blocks_movement = false;
	m_can_be_destroyed = false;
	m_can_be_summoned = false;
	m_hinders_movement = false;
	m_obscures_vision = false;
	m_type = k_obstacle_special;
}

inline bool	t_combat_object_model_root::blocks_movement() const
{
	return m_blocks_movement;
}

inline bool t_combat_object_model_root::can_be_destroyed() const
{
	return m_can_be_destroyed;
}

inline bool t_combat_object_model_root::can_be_summoned() const
{
	return m_can_be_summoned;
}

inline bool	t_combat_object_model_root::get_combat_has_changed()
{
	return t_combat_object_model_root::m_combat_has_changed;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline int t_combat_object_model_root::get_frames_per_second() const
{
	return m_frames_per_second;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline int t_combat_object_model_root::get_height() const
{
	return m_height;
}

inline int t_combat_object_model_root::get_ticks_per_frame() const
{
	return m_ticks_per_frame;
}

inline t_obstacle_type t_combat_object_model_root::get_type() const
{
	return m_type;
}

inline bool t_combat_object_model_root::is_underlay() const
{
	return m_underlay;
}

inline bool t_combat_object_model_root::hinders_movement() const
{
	return m_hinders_movement;
}

inline bool t_combat_object_model_root::obscures_vision() const
{
	return m_obscures_vision;
}

inline void t_combat_object_model_root::set_blocks_movement( bool arg )
{
	set_combat_has_changed();
	m_blocks_movement = arg;
}

inline void	t_combat_object_model_root::set_can_be_destroyed( bool arg )
{
	set_combat_has_changed();
	m_can_be_destroyed = arg;
}

inline void	t_combat_object_model_root::set_can_be_summoned( bool arg )
{
	set_combat_has_changed();
	m_can_be_summoned = arg;
}

inline void	t_combat_object_model_root::set_combat_has_changed(bool arg)
{
	t_combat_object_model_root::m_combat_has_changed = arg;
}

inline void t_combat_object_model_root::set_frames_per_second( int new_frames_per_second )
{
	set_combat_has_changed();
	assert(		new_frames_per_second >= k_min_frames_per_second
			&&	new_frames_per_second <= k_max_frames_per_second );
	m_ticks_per_frame = 1000 / new_frames_per_second;
	m_frames_per_second = new_frames_per_second;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline void t_combat_object_model_root::set_height( int new_height )
{
	set_combat_has_changed();
	assert(		new_height >= k_min_height
			&&	new_height <= k_max_height );
	m_height = new_height;
}

inline void t_combat_object_model_root::set_hinders_movement( bool arg )
{
	set_combat_has_changed();
	m_hinders_movement = arg;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline void t_combat_object_model_root::set_is_underlay( bool new_underlay )
{
	set_combat_has_changed();
	m_underlay = new_underlay;
}

inline void	t_combat_object_model_root::set_obscures_vision( bool arg )
{
	set_combat_has_changed();
	m_obscures_vision = arg;
}

inline void	t_combat_object_model_root::set_type( t_obstacle_type type )
{
	set_combat_has_changed();
	m_type = type;
}

// --------------------------------------------------------------------------
// t_combat_object_model_base class
// --------------------------------------------------------------------------
class t_combat_object_model_base : public t_combat_object_model_root
{
public:
	// Constructor/Destructor
	t_combat_object_model_base();

	// Static data
	enum { k_max_footprint_size = 10 };
	enum { k_min_footprint_size = 0 };

	// Member functions
	t_map_point_2d const&	get_footprint_size() const;
	bool					read( std::streambuf& stream );
	void					set_footprint_columns( int arg );
	void					set_footprint_rows( int arg );
	void					set_footprint_size( t_map_point_2d const& size );
	bool					write( std::streambuf& stream ) const;

private:
	// Data members
	t_map_point_2d  m_footprint_size;
};

// --------------------------------------------------------------------------
// t_combat_object_model_base inline members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline t_combat_object_model_base::t_combat_object_model_base()
	:	m_footprint_size( k_min_footprint_size, k_min_footprint_size )
{
}

inline t_map_point_2d const& t_combat_object_model_base::get_footprint_size() const
{
	return m_footprint_size;
}

inline void t_combat_object_model_base::set_footprint_size( t_map_point_2d const& size )
{
	assert(		size.column >= k_min_footprint_size
			&&	size.column <= k_max_footprint_size );
	assert(		size.row >= k_min_footprint_size
			&&	size.row <= k_max_footprint_size );
	m_footprint_size = size;
	set_combat_has_changed();
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline void t_combat_object_model_base::set_footprint_rows( int size )
{
	assert(		size >= k_min_footprint_size
			&&	size <= k_max_footprint_size );
	m_footprint_size.row = size;
	set_combat_has_changed();
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
inline void t_combat_object_model_base::set_footprint_columns( int size )
{
	assert(		size >= k_min_footprint_size
			&&	size <= k_max_footprint_size );
	m_footprint_size.column = size;
	set_combat_has_changed();
}


inline bool read( std::streambuf& stream, t_combat_object_model_base& model )
{
	return model.read( stream );
}

class t_combat_object_model_24 : public t_combat_object_model_base, 
                                 public t_image_sequence_24
{
public:
	// Member functions
	bool read( std::streambuf & stream );
	bool write( std::streambuf & stream ) const;
};

// --------------------------------------------------------------------------
// Inline free helper function for t_combat_object_model_24
// --------------------------------------------------------------------------
inline bool read( std::streambuf & stream, t_combat_object_model_24 & model )
{
	return model.read( stream );
}

// --------------------------------------------------------------------------
// t_resource_traits< t_combat_object_model_24 > specialization
// --------------------------------------------------------------------------

template <>
struct t_resource_traits< t_combat_object_model_base >
{
	static char const prefix[];
};

template <>
struct t_resource_traits< t_combat_object_model_24 >
{
	static char const prefix[];
	static char const extension[];
};

#endif // !defined( COMBAT_OBJECT_MODEL_H_INCLUDED )
